﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ComparedResults.cs" company="SMART business">
//   Copyright (c) 2014 All Rights Reserved
// </copyright>
// <summary>
//   The compared results.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ComparisonTool
{
    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;

    using CarlosAg.ExcelXmlWriter;

    using ComparisonTool.Interfaces;
    using ComparisonTool.Models;

    /// <summary>
    /// The compared results.
    /// </summary>
    public class ComparedResults : IComparedResults
    {
        /// <summary>
        /// The sections 1.
        /// </summary>
        private List<object> sections1;

        /// <summary>
        /// The sections 2.
        /// </summary>
        private List<object> sections2;

        /// <summary>
        /// The tabs 1.
        /// </summary>
        private List<object> tabs1;

        /// <summary>
        /// The tabs 2.
        /// </summary>
        private List<object> tabs2;

        /// <summary>
        /// The relation ships 1.
        /// </summary>
        private List<object> relationShips1;

        /// <summary>
        /// The relation ships 2.
        /// </summary>
        private List<object> relationShips2;

        /// <summary>
        /// The fields 1.
        /// </summary>
        private List<object> fields1;

        /// <summary>
        /// The fields 2.
        /// </summary>
        private List<object> fields2;

        /// <summary>
        /// Gets or sets the events 1.
        /// </summary>
        public List<object> Events1 { get; set; }

        /// <summary>
        /// Gets or sets the events 2.
        /// </summary>
        public List<object> Events2 { get; set; }

        /// <summary>
        /// Gets or sets the rules 1.
        /// </summary>
        public List<object> Rules1 { get; set; }

        /// <summary>
        /// Gets or sets the rules 2.
        /// </summary>
        public List<object> Rules2 { get; set; }

        /// <summary>
        /// Gets or sets the attributes 1.
        /// </summary>
        public Item Attributes1
        {
            get
            {
                return new Item(0, this.fields1);
            }

            set
            {
                switch (value.ComparingType)
                {
                    case (int)CompareType.Attributes:

                        this.fields1 = value.Items;
                        break;
                    case (int)CompareType.Sections:

                        this.sections1 = value.Items;
                        break;
                    case (int)CompareType.Tabs:

                        this.tabs1 = value.Items;
                        break;
                    case (int)CompareType.Relationships:

                        this.relationShips1 = value.Items;
                        break;
                }
            }
        }

        /// <summary>
        /// Gets or sets the attributes 2.
        /// </summary>
        public Item Attributes2
        {
            get
            {
                return new Item(0, this.fields2);
            }

            set
            {
                switch (value.ComparingType)
                {
                    case (int)CompareType.Attributes:
                        this.fields2 = value.Items;
                        break;
                    case (int)CompareType.Sections:

                        this.sections2 = value.Items;
                        break;
                    case (int)CompareType.Tabs:

                        this.tabs2 = value.Items;
                        break;
                    case (int)CompareType.Relationships:

                        this.relationShips2 = value.Items;
                        break;
                }
            }
        }

        public List<object> GetAttributes(int id, int compareType)
        {
            switch (compareType)
            {
                case (int)CompareType.Attributes:
                    return id == 1 ? this.fields1 : this.fields2;
                case (int)CompareType.Sections:
                    return id == 1 ? this.sections1 : this.sections2;
                case (int)CompareType.Tabs:
                    return id == 1 ? this.tabs1 : this.tabs2;
                case (int)CompareType.Relationships:
                    return id == 1 ? this.relationShips1 : this.relationShips2;
            }

            return null;
        }

        /// <summary>
        /// The upload results.
        /// </summary>
        /// <param name="xrm">
        /// The xrm.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool UploadResults(IXrm xrm)
        {
            var file = GetSavePath();

            var book = new Workbook();

            var styles = book.Styles;

            var orgNameStyle = styles.Add("HeaderStyle");
            orgNameStyle.Name = "HeaderStyle";
            orgNameStyle.Font.FontName = "Segoi UI";
            orgNameStyle.Font.Size = 14;
            orgNameStyle.Font.Bold = true;

            var sectionStyle = styles.Add("SectionStyle");
            sectionStyle.Name = "SectionStyle";
            sectionStyle.Font.FontName = "Segoi UI";
            sectionStyle.Font.Size = 11;
            sectionStyle.Interior.Color = "#E7E6E6";
            sectionStyle.Interior.Pattern = StyleInteriorPattern.Solid;
            sectionStyle.Font.Bold = true;

            var headerStyle = styles.Add("ColumnHeaderStyle");
            headerStyle.Name = "ColumnHeaderStyle";
            headerStyle.Font.FontName = "Segoi UI";
            headerStyle.Font.Size = 11;
            headerStyle.Interior.Color = "#C6EFCE";
            headerStyle.Interior.Pattern = StyleInteriorPattern.Solid;

            var simpleStyle = styles.Add("SimpleStyle");
            simpleStyle.Name = "SimpleStyle";
            simpleStyle.Font.FontName = "Segoi UI";
            simpleStyle.Font.Size = 11;

            const int FirstColumnIndex = 2;

            // Attributes, Sections, Tabs
            var wsheet1 = book.Worksheets.Add("Attributes, Sections, Tabs");
            wsheet1.Table.Rows.Add();

            var row1 = wsheet1.Table.Rows.Add();

            row1.Cells.Add(new WorksheetCell(xrm.GetOrgInfo(1)) { Index = FirstColumnIndex, MergeAcross = 4, StyleID = "HeaderStyle" });
            row1.Cells.Add();
            row1.Cells.Add(new WorksheetCell(xrm.GetOrgInfo(2)) { MergeAcross = 4, StyleID = "HeaderStyle" });

            this.AddComparedData(ref wsheet1, FirstColumnIndex, this.fields1, this.fields2, CompareType.Attributes);
            this.AddComparedData(ref wsheet1, FirstColumnIndex, this.sections1, this.sections2, CompareType.Sections);
            this.AddComparedData(ref wsheet1, FirstColumnIndex, this.tabs1, this.tabs2, CompareType.Tabs);
            this.AddComparedData(ref wsheet1, FirstColumnIndex, this.relationShips1, this.relationShips2, CompareType.Relationships);

            // Events
            var wsheet2 = book.Worksheets.Add("Events");
            wsheet2.Table.Rows.Add();

            var row2 = wsheet2.Table.Rows.Add();

            row2.Cells.Add(new WorksheetCell(xrm.GetOrgInfo(1)) { Index = FirstColumnIndex, MergeAcross = 4, StyleID = "HeaderStyle" });
            row2.Cells.Add();
            row2.Cells.Add(new WorksheetCell(xrm.GetOrgInfo(2)) { MergeAcross = 4, StyleID = "HeaderStyle" });

            this.AddComparedData(ref wsheet2, FirstColumnIndex, this.Events1, this.Events2, CompareType.Events);

            // Business_Rules
            var wsheet3 = book.Worksheets.Add("Business_Rules");
            wsheet3.Table.Rows.Add();

            var row3 = wsheet3.Table.Rows.Add();
            row3.Cells.Add(new WorksheetCell(xrm.GetOrgInfo(1)) { Index = FirstColumnIndex, MergeAcross = 4, StyleID = "HeaderStyle" });
            row3.Cells.Add();
            row3.Cells.Add(new WorksheetCell(xrm.GetOrgInfo(2)) { MergeAcross = 4, StyleID = "HeaderStyle" });

            this.AddComparedData(ref wsheet3, FirstColumnIndex, this.Rules1, this.Rules2, CompareType.BusinessRules);

            try
            {
                book.Save(file);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex.InnerException);
            }

            return true;
        }

        /// <summary>
        /// The get save path.
        /// </summary>
        /// <returns>
        /// The <see cref="string"/>.
        /// </returns>
        private static string GetSavePath()
        {
            var saveFileDialog = new SaveFileDialog
            {
                Filter = @"Excel Book|*.xls",
                FilterIndex = 2,
                RestoreDirectory = true
            };

            return saveFileDialog.ShowDialog() == DialogResult.OK ? saveFileDialog.FileName : string.Empty;
        }

        /// <summary>
        /// The add compared data.
        /// </summary>
        /// <param name="workSheet">
        /// The work book.
        /// </param>
        /// <param name="index">
        /// The org 1 i.
        /// </param>
        /// <param name="items1">
        /// The items 1.
        /// </param>
        /// <param name="items2">
        /// The items 2.
        /// </param>
        /// <param name="compareType">
        /// The compare type.
        /// </param>
        private void AddComparedData(ref Worksheet workSheet, int index, List<object> items1, List<object> items2, CompareType compareType)
        {
            this.AddSectionCaption(ref workSheet, index, compareType);

            if (items1 != null)
            {
                var count = items1.Count > items2.Count ? items1.Count : items2.Count;
                for (var i = 0; i < count; i++)
                {
                    var row = workSheet.Table.Rows.Add();
                    row.Cells.Add();

                    dynamic item1 = this.FormatItem(items1, i, compareType);

                    dynamic item2 = this.FormatItem(items2, i, compareType);

                    row.Cells.Add(item1.Column1);
                    row.Cells.Add(item1.Column2);
                    row.Cells.Add(item1.Column3);
                    row.Cells.Add(item1.Column4);
                    row.Cells.Add(item1.Column5);

                    row.Cells.Add();

                    row.Cells.Add(item2.Column1);
                    row.Cells.Add(item2.Column2);
                    row.Cells.Add(item2.Column3);
                    row.Cells.Add(item2.Column4);
                    row.Cells.Add(item2.Column5);
                }
            }

            workSheet.Table.Rows.Add();
        }

        private object FormatItem(List<object> items, int index, CompareType compareType)
        {
            dynamic item = index < items.Count ? items[index] : null;

            switch (compareType)
            {
                default:
                    return new
                    {
                        Column1 = item != null ? item.DisplayName : string.Empty,
                        Column2 = item != null ? item.Name : string.Empty,
                        Column3 = item != null ? item.TypeName : string.Empty,
                        Column4 = item != null ? item.IsReadOnly : string.Empty,
                        Column5 = item != null ? item.IsHidden : string.Empty,
                    };
                case CompareType.Events:
                    return new
                    {
                        Column1 = item != null ? item.Attribute : string.Empty,
                        Column2 = item != null ? item.AttributeDisplayName : string.Empty,
                        Column3 = item != null ? item.FunctionName : string.Empty,
                        Column4 = item != null ? item.LibraryName : string.Empty,
                        Column5 = item != null ? item.Name : string.Empty
                    };
                case CompareType.BusinessRules:
                    return new
                    {
                        Column1 = item != null ? item.CreatedBy : string.Empty,
                        Column2 = item != null ? item.RuleName : string.Empty,
                        Column3 = item != null ? item.State : string.Empty,
                        Column4 = item != null ? item.IsManaged : string.Empty,
                        Column5 = (dynamic)string.Empty
                    };
            }
        }

        /// <summary>
        /// The add section caption.
        /// </summary>
        /// <param name="workSheet">
        ///     The book.
        /// </param>
        /// <param name="index">
        ///     The index.
        /// </param>
        /// <param name="type">
        ///     The type.
        /// </param>
        private void AddSectionCaption(ref Worksheet workSheet, int index, CompareType type)
        {
            workSheet.Table.Rows.Add();
            var row = workSheet.Table.Rows.Add();

            row.Cells.Add(new WorksheetCell(type.ToString()) { Index = index, MergeAcross = 4, StyleID = "SectionStyle" });
            row.Cells.Add();
            row.Cells.Add(new WorksheetCell(type.ToString()) { MergeAcross = 4, StyleID = "SectionStyle" });

            workSheet.Table.Rows.Add();

            row = workSheet.Table.Rows.Add();

            switch (type)
            {
                case CompareType.Attributes:
                case CompareType.Sections:
                case CompareType.Tabs:
                case CompareType.Relationships:

                    row.Cells.Add(new WorksheetCell("Display Name") { Index = index, StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Name") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Type") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Is Read Only") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Is Hidden") { StyleID = "ColumnHeaderStyle" });

                    row.Cells.Add();
                    row.Cells.Add(new WorksheetCell("Display Name") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Name") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Type") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Is Read Only") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Is Hidden") { StyleID = "ColumnHeaderStyle" });

                    break;
                case CompareType.Events:

                    row.Cells.Add(new WorksheetCell("Attribute") { Index = index, StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Attribute DisplayName") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Function Name") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Library Name") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Name") { StyleID = "ColumnHeaderStyle" });

                    row.Cells.Add();

                    row.Cells.Add(new WorksheetCell("Attribute") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Attribute DisplayName") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Function Name") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Library Name") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Name") { StyleID = "ColumnHeaderStyle" });

                    break;

                case CompareType.BusinessRules:

                    row.Cells.Add(new WorksheetCell("Created By") { Index = index, StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Business Rule Name") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("State") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Is Managed") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add();

                    row.Cells.Add();

                    row.Cells.Add(new WorksheetCell("Created By") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Business Rule Name") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("State") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add(new WorksheetCell("Is Managed") { StyleID = "ColumnHeaderStyle" });
                    row.Cells.Add();

                    break;
            }
        }
    }
}
